package com.zxy.demo.delay;

import java.util.Map;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.zxy.demo.delay.pojo.BaseDelayTask;
import com.zxy.demo.redis.RedisUtil;
import com.zxy.demo.spring.SpringContextUtils;

/**
 * 延时任务管理类（是个单例类）
 * @author ZENG.XIAO.YAN
 * @date   2018年6月6日
 * 
 */
public class DelayTaskManager {
	public static final String TASK_REDIS_KEY = "ZXY:task";
	private RedisUtil redisUtil;
	
	/** 创建一个最初为空的新 DelayQueue */
    private DelayQueue<BaseDelayTask> delayQueue = new DelayQueue<BaseDelayTask>();
    
	/** 私有化构造器 */
	private DelayTaskManager() {
		super();
	}
	
	 /** 写一个静态内部类，里面实例化外部类 */
    private static class LazyHolder {
        private static final DelayTaskManager INSTANCE = new DelayTaskManager();
    }
    
	/** 获取实例的方法 */
	public static DelayTaskManager getInstance() {
		return LazyHolder.INSTANCE;
	}
    
	/**
	 * 添加任务到队列
	 * @param task
	 * @return
	 */
	public  boolean add(BaseDelayTask task) {
		try {
			delayQueue.add(task);
			// 生存时间设置为1天,一般服务器宕机了应该也会在1天之内重启
			redisUtil.hset(TASK_REDIS_KEY, String.valueOf(task.getId()), task, 24*60*60);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	/**
	 * 从队列中删除任务
	 * @param task
	 * @return
	 */
	public boolean remove(BaseDelayTask task) {
		try {
			delayQueue.remove(task);
			redisUtil.hdel(TASK_REDIS_KEY, String.valueOf(task.getId()));
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	/**
	 * 从队列中删除任务
	 * @param taskId
	 * @return
	 */
	public boolean remove(Long taskId) {
		try {
			BaseDelayTask[] array = delayQueue.toArray(new BaseDelayTask[]{});
			if(null == array || array.length < 1) {
				return false;
			}
			BaseDelayTask targetTask = null;
			for (BaseDelayTask baseDelayTask : array) {
				if(taskId.equals(baseDelayTask.getId())) {
					targetTask = baseDelayTask;
					break;
				}
			}
			if(null != targetTask) {
				delayQueue.remove(targetTask);
				redisUtil.hdel(TASK_REDIS_KEY, String.valueOf(taskId));
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	/** 从对列中取任务并执行 ，不想让其他类调用，直接私有化*/
	private void execute() {
		System.out.println("^^------执行延时任务类已启动-----^^^^^^");
		int threadNum = Runtime.getRuntime().availableProcessors();
		if(threadNum < 30) {
			threadNum = 30;
		}
		System.out.println("^^------线程池大小为：" + threadNum + "-----^^^^^^");
		ExecutorService pool = Executors.newFixedThreadPool(threadNum);
		while (true) {
			Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
			System.out.println("总线程数--------------" + map.size());
			System.out.println("队列任务数--------------" + delayQueue.size());
			try {
				// 从延迟队列中取过期的对象,如果没有对象过期则队列一直等待
				BaseDelayTask task = delayQueue.take();
				if (task != null) {
					pool.submit(task);
					// 注意，删除redis中的任务应该在task对象的run方法里面删除
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	/** 初始化方法 */
	private void init() {
		// 从redis中取出那些持久化的任务，然后将任务重新加入到队列中。
		Map<Object, Object> map = redisUtil.hmget(TASK_REDIS_KEY);
		if(null != map && map.size() > 0) {
			System.out.println("容器初始化^^^^^^^^^redis中有" + map.size() + "个任务未执行");
			for (Object key : map.keySet()) {
				delayQueue.add((BaseDelayTask) map.get(key));
			}
		}
	}
	
	/**
	 * 启动方法
	 * @see 该方法用在web或者Spring容器启动后执行一次
	 */
	public void start() {
		// 从Spring容器中拿RedisUtil对象
		this.redisUtil = SpringContextUtils.getBean(RedisUtil.class);
		
		/** init方法和execute方法均开线程异步执行 */
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				// 开启线程调用初始化方法
				init();
			}
		});
		t1.start();
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					// 保证init线程执行完毕
					t1.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// 调用执行方法
				execute();
			}
		});
		t2.start();
	}
}
